#include <stdio.h>
#include <string.h>
#include <stdint.h>

#include "main.h"
#include "Liot_AT.h"

static uint8_t g_mqtt_status = 0;

void Liot_AT_mqtt_callback(Liot_AT_mqtt_urc_event_t event, uint8_t id, uint16_t msgid, uint8_t *topic, uint8_t *data, uint16_t len)
{
    switch(event)
    {
        case AT_MQTT_URC_STATS:
        {
            break;
        }
        case AT_MQTT_URC_RECV:
        {
            AT_LOGD("mqtt recv msgid : %d\r\n", msgid);
            AT_LOGD("mqtt recv topic : %s\r\n", topic);
            AT_LOGD("mqtt recv data : %s\r\n", data);
            break;
        }
        default:break;
    }
}

static void _mqtt_set_status(uint8_t status)
{
    g_mqtt_status = status;
}

uint8_t Liot_check_mqtt_status(void)
{
    return g_mqtt_status;
}

AT_errorcode_t Liot_AT_mqtt_open(uint8_t id, Liot_AT_mqtt_cfg_t *cfg, int8_t *result)
{
    uint8_t cmd[128] = {0};
    uint8_t *offset = NULL;

    int32_t res = 0;

    if(cfg == NULL)
    {
        return AT_INVALID_PARAM;
    }
    sprintf(cmd, "AT+LMQTTOPEN=0,\"%s\",%d\r\n", cfg->host, cfg->port);
//    sprintf(cmd, "AT+LMQTTOPEN=%d,\"%s\",%d\r\n", id, cfg->host, cfg->port);
    Liot_AT_cmd_send(cmd, strlen(cmd));
    if(Liot_AT_wait_rsp(160000) != AT_OK)
    {
        return AT_TIMEOUT;
    }
    if(strstr(g_at_rsp, "ERROR") != NULL)
    {
        Liot_AT_get_rsp_error_reason(g_at_rsp);
        return AT_RECV_ERROR;
    }
    offset = strstr(g_at_rsp, ":");
    if(offset == NULL)
    {
        if(Liot_AT_wait_rsp(5000) != AT_OK)
        {
            return AT_TIMEOUT;
        }
    }
//    Liot_AT_rsp_get_param(g_at_rsp, "+LMQTTOPEN", 0, AT_PARAM_TYPE_DEC, &id);
    Liot_AT_rsp_get_param(g_at_rsp, "+LMQTTOPEN", 1, AT_PARAM_TYPE_DEC, &res);

    if(result != NULL)
    {
        *result = res;
    }
    if(res == -1)
    {
        AT_LOGE("MQTT open failed!\r\n");
        return AT_OK;
    }
    else
    {
        AT_LOGI("MQTT open success!\r\n");
        _mqtt_set_status(1);
        return AT_OK;
    }
}

AT_errorcode_t Liot_AT_mqtt_close(uint8_t id, uint8_t *result)
{
    uint8_t cmd[32] = {0};
    uint8_t *offset = NULL;
    uint32_t res = 0;

    sprintf(cmd, "AT+LMQTTCLOSE=0\r\n");
//    sprintf(cmd, "AT+LMQTTCLOSE=%d\r\n", id);
    Liot_AT_cmd_send(cmd, strlen(cmd));
    if(Liot_AT_wait_rsp(5000) != AT_OK)
    {
        return AT_TIMEOUT;
    }
    if(strstr(g_at_rsp, "ERROR") != NULL)
    {
        Liot_AT_get_rsp_error_reason(g_at_rsp);
        return AT_RECV_ERROR;
    }
    offset = strstr(g_at_rsp, ":");
    if(offset == NULL)
    {
        if(Liot_AT_wait_rsp(5000) != AT_OK)
        {
            return AT_TIMEOUT;
        }
    }

    Liot_AT_rsp_get_param(g_at_rsp, "+LMQTTCLOSE", 1, AT_PARAM_TYPE_DEC, &res);
    if(result != NULL)
    {
        *result = res;
    }
    if(res == 1)
    {
        AT_LOGE("MQTT close failed!\r\n");
        return AT_OK;
    }
    else
    {
        AT_LOGI("MQTT close success!\r\n");
        _mqtt_set_status(0);
        return AT_OK;
    }
}

AT_errorcode_t Liot_AT_mqtt_connect(uint8_t id, Liot_AT_mqtt_conn_cfg_t *cfg, uint8_t *result)
{
    uint8_t cmd[128] = {0};
    uint8_t *offset = NULL;
    uint32_t conn_result = 0;
    uint32_t res = 0;

    if(cfg == NULL)
    {
        sprintf(cmd, "AT+LMQTTCONN=0\r\n");
//        sprintf(cmd, "AT+LMQTTCONN=%d\r\n", id);
    }
    else
    {
        sprintf(cmd, "AT+LMQTTCONN=0,\"%s\",\"%s\",\"%s\"\r\n", cfg->clientID, cfg->username, cfg->password);
//        sprintf(cmd, "AT+LMQTTCONN=%d,\"%s\",\"%s\",\"%s\"\r\n", id, cfg.clientID, cfg.username, cfg.password);
    }
    Liot_AT_cmd_send(cmd, strlen(cmd));
    if(Liot_AT_wait_rsp(30000) != AT_OK)
    {
        return AT_TIMEOUT;
    }
    if(strstr(g_at_rsp, "ERROR") != NULL)
    {
        Liot_AT_get_rsp_error_reason(g_at_rsp);
        return AT_RECV_ERROR;
    }
    offset = strstr(g_at_rsp, ":");
    if(offset == NULL)
    {
        if(Liot_AT_wait_rsp(5000) != AT_OK)
        {
            return AT_TIMEOUT;
        }
    }

//    Liot_AT_rsp_get_param(g_at_rsp, "+LMQTTCONN", 0, AT_PARAM_TYPE_DEC, &id);
    Liot_AT_rsp_get_param(g_at_rsp, "+LMQTTCONN", 1, AT_PARAM_TYPE_DEC, &conn_result);
    Liot_AT_rsp_get_param(g_at_rsp, "+LMQTTCONN", 2, AT_PARAM_TYPE_DEC, &res);

    if(result != NULL)
    {
        *result = res;
    }
    if(conn_result == 0)
    {
        AT_LOGI("MQTT connect success!\r\n");
        return AT_OK;
    }
    else if(conn_result == 1)
    {
        AT_LOGE("MQTT connect failed! reason: %d\r\n", *result);
        return AT_OK;
    }
}

AT_errorcode_t Liot_AT_mqtt_disconnect(uint8_t id, uint8_t *result)
{
    uint8_t cmd[32] = {0};
    uint32_t res = 0;

    sprintf(cmd, "AT+LMQTTDISC=0\r\n");
//    sprintf(cmd, "AT+LMQTTDISC=%d\r\n", id);
    Liot_AT_cmd_send(cmd, strlen(cmd));
    if(Liot_AT_wait_rsp(5000) != AT_OK)
    {
        return AT_TIMEOUT;
    }
    if(strstr(g_at_rsp, "ERROR") != NULL)
    {
        Liot_AT_get_rsp_error_reason(g_at_rsp);
        return AT_RECV_ERROR;
    }

    Liot_AT_rsp_get_param(g_at_rsp, "+LMQTTCONN", 1, AT_PARAM_TYPE_DEC, &res);

    if(result != NULL)
    {
        *result = res;
    }
    if(res == 0)
    {
        AT_LOGI("MQTT disconnect success!\r\n");
        return AT_OK;
    }
    else
    {
        AT_LOGE("MQTT disconnect failed!\r\n");
        return AT_OK;
    }
}

AT_errorcode_t Liot_AT_mqtt_subscribe(uint8_t id, Liot_AT_mqtt_topic_cfg_t *cfg, uint8_t *result)
{
    uint8_t cmd[128] = {0};
    uint8_t *offset = NULL;
    uint32_t res = 0;

    if(cfg == NULL)
    {
        return AT_INVALID_PARAM;
    }

    sprintf(cmd, "AT+LMQTTSUBUNSUB=0,0,%d,\"%s\",%d\r\n", cfg->msgid, cfg->topic, cfg->qos);
//    sprintf(cmd, "AT+LMQTTSUBUNSUB=%d,0,%d,\"%s\",%d", id, cfg->msgid, cfg->topic, cfg->qos);
    Liot_AT_cmd_send(cmd, strlen(cmd));
    if(Liot_AT_wait_rsp(30000) != AT_OK)
    {
        return AT_TIMEOUT;
    }
    if(strstr(g_at_rsp, "ERROR") != NULL)
    {
        Liot_AT_get_rsp_error_reason(g_at_rsp);
        return AT_RECV_ERROR;
    }
    offset = strstr(g_at_rsp, ":");
    if(offset == NULL)
    {
        if(Liot_AT_wait_rsp(5000) != AT_OK)
        {
            return AT_TIMEOUT;
        }
    }

    Liot_AT_rsp_get_param(g_at_rsp, "+LMQTTSUBUNSUB", 2, AT_PARAM_TYPE_DEC, &res);

    if(result != NULL)
    {
        *result = res;
    }
    if(res == 0)
    {
        AT_LOGI("MQTT subscribe success!\r\n");
        return AT_OK;
    }
    else
    {
        AT_LOGE("MQTT subscribe failed!\r\n");
        return AT_OK;
    }
}

AT_errorcode_t Liot_AT_mqtt_unsubscribe(uint8_t id, Liot_AT_mqtt_topic_cfg_t *cfg, uint8_t *result)
{
    uint8_t cmd[128] = {0};
    uint8_t *offset = NULL;
    uint32_t res = 0;

    if(cfg == NULL || result == NULL)
    {
        return AT_INVALID_PARAM;
    }

    sprintf(cmd, "AT+LMQTTSUBUNSUB=0,1,%d,\"%s\",%d\r\n", cfg->msgid, cfg->topic, cfg->qos);
//    sprintf(cmd, "AT+LMQTTSUBUNSUB=%d,1,%d,\"%s\",%d", id, cfg->msgid, cfg->topic, cfg->qos);
    Liot_AT_cmd_send(cmd, strlen(cmd));
    if(Liot_AT_wait_rsp(30000) != AT_OK)
    {
        return AT_TIMEOUT;
    }
    if(strstr(g_at_rsp, "ERROR") != NULL)
    {
        Liot_AT_get_rsp_error_reason(g_at_rsp);
        return AT_RECV_ERROR;
    }
    offset = strstr(g_at_rsp, ":");
    if(offset == NULL)
    {
        if(Liot_AT_wait_rsp(5000) != AT_OK)
        {
            return AT_TIMEOUT;
        }
    }

    Liot_AT_rsp_get_param(g_at_rsp, "+LMQTTSUBUNSUB", 2, AT_PARAM_TYPE_DEC, &res);

    if(result != NULL)
    {
        *result = res;
    }
    if(res == 0)
    {
        AT_LOGI("MQTT unsubscribe success!\r\n");
        return AT_OK;
    }
    else
    {
        AT_LOGE("MQTT unsubscribe failed!\r\n");
        return AT_OK;
    }
}

AT_errorcode_t Liot_AT_mqtt_publish(uint8_t id, Liot_AT_mqtt_topic_cfg_t *cfg, uint8_t *data, uint16_t len, uint8_t retain, uint8_t *result)
{
    uint8_t cmd[1152] = {0};
    uint8_t *offset = NULL;
    uint32_t res = 0;

    if(cfg == NULL || data == NULL)
    {
        return AT_INVALID_PARAM;
    }

    sprintf(cmd, "AT+LMQTTPUB=0,%d,%d,%d,\"%s\",%d,\"%s\"\r\n", cfg->msgid, cfg->qos, retain, cfg->topic, len, data);
//    sprintf(cmd, "AT+LMQTTPUB=%d,%d,%d,%d,\"%s\",%d,\"%s\"\r\n", id, cfg->msgid, cfg->qos, retain, cfg->topic, len, data);

    Liot_AT_cmd_send(cmd, strlen(cmd));
    if(Liot_AT_wait_rsp(30000) != AT_OK)
    {
        return AT_TIMEOUT;
    }
    if(strstr(g_at_rsp, "ERROR") != NULL)
    {
        Liot_AT_get_rsp_error_reason(g_at_rsp);
        return AT_RECV_ERROR;
    }
    offset = strstr(g_at_rsp, ":");
    if(offset == NULL)
    {
        if(Liot_AT_wait_rsp(5000) != AT_OK)
        {
            return AT_TIMEOUT;
        }
    }

    Liot_AT_rsp_get_param(g_at_rsp, "+LMQTTPUB", 2, AT_PARAM_TYPE_DEC, &res);

    if(result != NULL)
    {
        *result = res;
    }
    if(res == 0 || res == 1)
    {
        AT_LOGI("MQTT publish success!\r\n");
        return AT_OK;
    }
    else
    {
        AT_LOGE("MQTT publish failed!\r\n");
        return AT_OK;
    }
}

AT_errorcode_t Liot_AT_mqtt_publishex(uint8_t id, Liot_AT_mqtt_topic_cfg_t *cfg, uint8_t *data, uint16_t len, uint8_t retain, uint32_t interval, uint8_t *result)
{
    uint8_t cmd[1152] = {0};
    uint8_t *offset = NULL;
    uint32_t res = 0;

    if(cfg == NULL || data == NULL)
    {
        return AT_INVALID_PARAM;
    }

    sprintf(cmd, "AT+LMQTTPUBEX=%d,0,%d,%d,%d,\"%s\",%d,\"%s\"\r\n", interval, cfg->msgid, cfg->qos, retain, cfg->topic, len, data);
//    sprintf(cmd, "AT+LMQTTPUBEX=%d,%d,%d,%d,%d,\"%s\",%d,\"%s\"\r\n", interval, id, cfg->msgid, cfg->qos, retain, cfg->topic, len, data);
    Liot_AT_cmd_send(cmd, strlen(cmd));
    if(Liot_AT_wait_rsp(30000) != AT_OK)
    {
        return AT_TIMEOUT;
    }
    if(strstr(g_at_rsp, "ERROR") != NULL)
    {
        Liot_AT_get_rsp_error_reason(g_at_rsp);
        return AT_RECV_ERROR;
    }
    offset = strstr(g_at_rsp, ":");
    if(offset == NULL)
    {
        if(Liot_AT_wait_rsp(5000) != AT_OK)
        {
            return AT_TIMEOUT;
        }
    }

    Liot_AT_rsp_get_param(g_at_rsp, "+LMQTTPUB", 2, AT_PARAM_TYPE_DEC, &res);

    if(result != NULL)
    {
        *result = res;
    }
    if(res == 0 || res == 1)
    {
        AT_LOGI("MQTT publish success!\r\n");
        return AT_OK;
    }
    else
    {
        AT_LOGE("MQTT publish failed!\r\n");
        return AT_OK;
    }
}

AT_errorcode_t Liot_AT_mqtt_read(uint32_t *id, uint32_t *msgid, uint8_t *topic, uint8_t *data, uint32_t *len)
{
    uint8_t cmd[] = "AT+LMQTTREAD\r\n";

    if(msgid == NULL || topic == NULL || data == NULL || len == NULL)
    {
        return AT_INVALID_PARAM;
    }

    Liot_AT_cmd_send(cmd, strlen(cmd));
    if(Liot_AT_wait_rsp(5000) != AT_OK)
    {
        return AT_TIMEOUT;
    }
    if(strstr(g_at_rsp, "ERROR") != NULL)
    {
        Liot_AT_get_rsp_error_reason(g_at_rsp);
        return AT_RECV_ERROR;
    }

    Liot_AT_rsp_get_param(g_at_rsp, "+LMQTTREAD", 0, AT_PARAM_TYPE_DEC, id);
    Liot_AT_rsp_get_param(g_at_rsp, "+LMQTTREAD", 1, AT_PARAM_TYPE_DEC, msgid);
    Liot_AT_rsp_get_param(g_at_rsp, "+LMQTTREAD", 2, AT_PARAM_TYPE_STR, topic);
    Liot_AT_rsp_get_param(g_at_rsp, "+LMQTTREAD", 3, AT_PARAM_TYPE_STR, data);

    *len = strlen(data);

    return AT_OK;
}


